reference.hpp
namespace type_safe
{
template <typename T, bool XValue>
class object_ref;
template <typename T, bool XValue>
struct optional_storage_policy_for<object_ref<T, XValue>>;
//=== Object reference comparison ===//
template <typename T, typename U, bool XValue>
constexpr )>bool operator==(const object_ref<T, XValue>& a, const object_ref<U, XValue>& b) noexcept;
template <typename T, typename U, bool XValue>
constexpr )>bool operator==(const object_ref<T, XValue>& a, U& b) noexcept;
template <typename T, typename U, bool XValue>
constexpr )>bool operator==(const T& a, const object_ref<U, XValue>& b) noexcept;
template <typename T, typename U, bool XValue>
constexpr )>bool operator!=(const object_ref<T, XValue>& a, const object_ref<U, XValue>& b) noexcept;
template <typename T, typename U, bool XValue>
constexpr )>bool operator!=(const object_ref<T, XValue>& a, U& b) noexcept;
template <typename T, typename U, bool XValue>
constexpr )>bool operator!=(const T& a, const object_ref<U, XValue>& b) noexcept;
template <typename T, bool XValue, typename Func, typename ... Args>
void with(const object_ref<T, XValue>& ref, Func&& f, Args&&... additional_args);
template <typename T>
constexpr object_ref<T> ref(T& obj) noexcept;
template <typename T>
constexpr object_ref<const T> cref(const T& obj) noexcept;
template <typename T>
using xvalue_ref = object_ref<T, true>;
template <typename T>
constexpr xvalue_ref<T> xref(T& obj) noexcept;
template <typename T>
constexpr typename std::remove_const<T>::type copy(const object_ref<T>& obj);
template <typename T>
constexpr T move(const xvalue_ref<T>& obj) noexcept('hidden');
template <typename T, bool XValue = false>
class array_ref;
template <typename T, bool XValue, typename Func, typename ... Args>
void with(const array_ref<T, XValue>& ref, Func&& f, Args&&... additional_args);
template <typename T, std::size_t Size>
array_ref<T> ref(T(&)[Size] arr) noexcept;
template <typename T>
array_ref<T> ref(T* begin, T* end) noexcept;
template <typename T>
array_ref<T> ref(T* array, size_t size) noexcept;
template <typename T, std::size_t Size>
array_ref<const T> cref(const T(&)[Size] arr) noexcept;
template <typename T>
array_ref<const T> cref(const T* begin, const T* end) noexcept;
template <typename T>
array_ref<const T> cref(const T* array, size_t size) noexcept;
template <typename T>
using array_xvalue_ref = array_ref<T, true>;
template <typename T, std::size_t Size>
array_xvalue_ref<T> xref(T(&)[Size] arr) noexcept;
template <typename T>
array_xvalue_ref<T> xref(T* begin, T* end) noexcept;
template <typename T>
array_xvalue_ref<T> xref(T* array, size_t size) noexcept;
template <typename Return, typename ... Args>
class function_ref<Return(Args...)>;
}
type_safe::object_ref
template <typename T, bool XValue>
class object_ref
{
public:
using value_type = T;
using reference_type = typename std::conditional<XValue, T&&, T&>::type;
template <typename U>
)>object_ref& operator=(const object_ref<U>& obj) noexcept;
constexpr reference_type get() const noexcept;
constexpr reference_type operator*() const noexcept;
constexpr T* operator->() const noexcept;
template <typename Func, typename ... Args>
'hidden' map(Func&& f, Args&&... args);
};
A reference to an object of some type T
.
Unlike std::reference_wrapper it does not try to model reference semantics, instead it is basically a non-null pointer to a single object. This allows rebinding on assignment. Apart from the different access syntax it can be safely used instead of a reference, and is safe for all kinds of containers.
If the given type is const
, it will only return a const
reference, but then XValue
must be false
.
If XValue
is true
, dereferencing will std::move() the object, modelling a reference to an expiring lvalue.
Notes: T
is the type without the reference, ie. object_ref<int>
.
type_safe::object_ref::operator=
(1) template <typename U>
)>object_ref& operator=(const object_ref<U>& obj) noexcept;
type_safe::object_ref::get
(1) constexpr reference_type get() const noexcept;
(2) constexpr reference_type operator*() const noexcept;
Returns: A native reference to the referenced object. if XValue
is true, this will be an rvalue reference, else an lvalue reference.
type_safe::object_ref::operator->
constexpr T* operator->() const noexcept;
Member access operator.
type_safe::object_ref::map
template <typename Func, typename ... Args>
'hidden' map(Func&& f, Args&&... args);
Effects: Invokes the function with the referred object followed by the arguments.
Returns: A ts::object_ref to the result of the function, if *this
is an xvalue reference, the result is as well.
Requires: The function must return an lvalue or another ts::object_ref object.
type_safe::optional_storage_policy_for<object_ref<T, XValue>>
[optional]template <typename T, bool XValue>
struct optional_storage_policy_for<object_ref<T, XValue>>
{
using type = reference_optional_storage<T, XValue>;
};
Sets the ts::basic_optional storage policy for ts::object_ref to ts::reference_optional_storage.
It will be used when the optional is rebound.
(1) template <typename T, typename U, bool XValue>
constexpr )>bool operator==(const object_ref<T, XValue>& a, const object_ref<U, XValue>& b) noexcept;
(2) template <typename T, typename U, bool XValue>
constexpr )>bool operator==(const object_ref<T, XValue>& a, U& b) noexcept;
(3) template <typename T, typename U, bool XValue>
constexpr )>bool operator==(const T& a, const object_ref<U, XValue>& b) noexcept;
(4) template <typename T, typename U, bool XValue>
constexpr )>bool operator!=(const object_ref<T, XValue>& a, const object_ref<U, XValue>& b) noexcept;
(5) template <typename T, typename U, bool XValue>
constexpr )>bool operator!=(const object_ref<T, XValue>& a, U& b) noexcept;
(6) template <typename T, typename U, bool XValue>
constexpr )>bool operator!=(const T& a, const object_ref<U, XValue>& b) noexcept;
Comparison operator for ts::object_ref.
Two references are equal if both refer to the same object. A reference is equal to an object if the reference refers to that object.
Notes: These functions do not participate in overload resolution if the types are not compatible (i.e. const/non-const or derived).
type_safe::with
template <typename T, bool XValue, typename Func, typename ... Args>
void with(const object_ref<T, XValue>& ref, Func&& f, Args&&... additional_args);
With operation for ts::object_ref.
Effects: Calls the operator()
of f
passing it *ref
and the additional arguments.
type_safe::ref
(1) template <typename T>
constexpr object_ref<T> ref(T& obj) noexcept;
(2) template <typename T>
constexpr object_ref<const T> cref(const T& obj) noexcept;
Creates a (const) ts::object_ref.
Returns: A ts::object_ref to the given object.
type_safe::xvalue_ref
template <typename T>
using xvalue_ref = object_ref<T, true>;
Convenience alias of ts::object_ref where XValue
is true
.
type_safe::xref
template <typename T>
constexpr xvalue_ref<T> xref(T& obj) noexcept;
Creates a ts::xvalue_ref.
Returns: A ts::xvalue_ref to the given object.
type_safe::copy
(1) template <typename T>
constexpr typename std::remove_const<T>::type copy(const object_ref<T>& obj);
(2) template <typename T>
constexpr T move(const xvalue_ref<T>& obj) noexcept('hidden');
Returns: A new object containing a copy of the referenced object. It will use the copy (1)/move constructor (2).
Throws: Anything thrown by the copy (1)/move (2) constructor.
type_safe::array_ref
template <typename T, bool XValue = false>
class array_ref
{
public:
using value_type = T;
using reference_type = typename std::conditional<XValue, T&&, T&>::type;
using iterator = T*;
array_ref(std::nullptr_t);
void assign(std::nullptr_t) noexcept;
array_ref(T* begin, T* end) noexcept;
void assign(T* begin, T* end) noexcept;
array_ref(T* array, size_t size) noexcept;
void assign(T* array, size_t size) noexcept;
template <std::size_t Size>
array_ref(T(&)[Size] arr);
template <std::size_t Size>
void assign(T(&)[Size] arr) noexcept;
iterator begin() const noexcept;
iterator end() const noexcept;
T* data() const noexcept;
size_t size() const noexcept;
reference_type operator[](index_t i) const noexcept;
};
A reference to an array of objects of type T
.
It is a simple pointer + size pair that allows reference access to each element in the array. An "array" here is any contiguous storage (so C arrays, std::vector, etc.). It does not allow changing the size of the array, only the individual elements. Like ts::object_ref it can be safely used in containers.
If the given type is const
, it will only return a const
reference to each element, but then XValue
must be false
.
If XValue
is true
, dereferencing will std::move() the object, modelling a reference to an expiring lvalue.
Notes: T
is the type stored in the array, so array_ref<int>
to reference a contiguous storage of int
s. \notes Unlike the other types it isn't technically non-null, as it may contain an empty array. But the range [data(), data() + size)
will always be valid.
type_safe::array_ref::array_ref
(1) array_ref(std::nullptr_t);
(2) void assign(std::nullptr_t) noexcept;
Effects: Sets the reference to an empty array.
type_safe::array_ref::array_ref
(1) array_ref(T* begin, T* end) noexcept;
(2) void assign(T* begin, T* end) noexcept;
Effects: Sets the reference to the memory range [begin, end)
.
Requires: begin <= end
.
type_safe::array_ref::array_ref
(1) array_ref(T* array, size_t size) noexcept;
(2) void assign(T* array, size_t size) noexcept;
Effects: Sets the reference to the memory range [array, array + size)
.
Requires: array
must not be nullptr
unless size
is 0
.
type_safe::array_ref::array_ref
(1) template <std::size_t Size>
array_ref(T(&)[Size] arr);
(2) template <std::size_t Size>
void assign(T(&)[Size] arr) noexcept;
Effects: Sets the reference to the C array.
type_safe::array_ref::begin
iterator begin() const noexcept;
Returns: An iterator to the beginning of the array.
type_safe::array_ref::end
iterator end() const noexcept;
Returns: An iterator one past the last element of the array.
type_safe::array_ref::data
T* data() const noexcept;
Returns: A pointer to the beginning of the array. If size()
isn't zero, the pointer is guaranteed to be non-null.
type_safe::array_ref::size
size_t size() const noexcept;
Returns: The number of elements in the array.
type_safe::array_ref::operator[]
reference_type operator[](index_t i) const noexcept;
Returns: A (rvalue
if Xvalue
is true
) reference to the i
th element of the array.
Requires: i < size()
.
type_safe::with
template <typename T, bool XValue, typename Func, typename ... Args>
void with(const array_ref<T, XValue>& ref, Func&& f, Args&&... additional_args);
With operation for ts::array_ref.
Effects: For every element of the array in order, it will invoke f
, passing it the current element and the additional arguments. / If XValue
is true
, it will pass an rvalue reference to the element, allowing it to be moved from.
type_safe::ref
(1) template <typename T, std::size_t Size>
array_ref<T> ref(T(&)[Size] arr) noexcept;
(2) template <typename T>
array_ref<T> ref(T* begin, T* end) noexcept;
(3) template <typename T>
array_ref<T> ref(T* array, size_t size) noexcept;
Creates a ts::array_ref.
Returns: The reference created by forwarding the parameter(s) to the constructor.
type_safe::cref
(1) template <typename T, std::size_t Size>
array_ref<const T> cref(const T(&)[Size] arr) noexcept;
(2) template <typename T>
array_ref<const T> cref(const T* begin, const T* end) noexcept;
(3) template <typename T>
array_ref<const T> cref(const T* array, size_t size) noexcept;
Creates a ts::array_ref to const
.
Returns: The reference created by forwarding the parameter(s) to the constructor.
type_safe::array_xvalue_ref
template <typename T>
using array_xvalue_ref = array_ref<T, true>;
Convenience alias for ts::array_ref where XValue
is true
.
type_safe::xref
(1) template <typename T, std::size_t Size>
array_xvalue_ref<T> xref(T(&)[Size] arr) noexcept;
(2) template <typename T>
array_xvalue_ref<T> xref(T* begin, T* end) noexcept;
(3) template <typename T>
array_xvalue_ref<T> xref(T* array, size_t size) noexcept;
Creates a ts::array_xvalue_ref.
Returns: The reference created by forwarding the parameter(s) to the constructor.
type_safe::function_ref<Return(Args...)>
template <typename Return, typename ... Args>
class function_ref<Return(Args...)>
{
public:
using signature = Return(Args...);
function_ref(Return(*)(Args...) fptr);
template <typename Return2, typename ... Args2>
function_ref(Return2(*)(Args2...) fptr);
template <typename Functor>
function_ref(const Functor& f);
template <typename Functor>
function_ref(Functor& f);
template <typename Return2, typename ... Args2>
function_ref(const function_ref<Return2(Args2...)>& other, 'hidden' = 0);
template <typename Functor>
void assign(Functor&& f) noexcept;
Return operator()(Args... args) const;
};
A reference to a function.
This is a lightweight reference to a function. It can refer to any function that is compatible with given signature.
A function is compatible if it is callable with regular function call syntax from the given argument types, and its return type is either implicitly convertible to the specified return type or the specified return type is void
.
In general it will store a pointer to the functor, requiring an lvalue. But if it is created with a function pointer or something convertible to a function pointer, it will store the function pointer itself. This allows creating it from stateless lambdas.
Notes: Due to implementation reasons, it does not support member function pointers, as it requires regular function call syntax. Create a reference to the object returned by std::mem_fn, if that is required.
type_safe::function_ref<Return(Args...)>::function_ref
function_ref(Return(*)(Args...) fptr);
Effects: Creates a reference to the function specified by the function pointer.
Requires: fptr
must not be nullptr
.
Notes: (2) only participates in overload resolution if the type of the function is compatible with the specified signature. \group function_ptr_ctor
type_safe::function_ref<Return(Args...)>::function_ref
(1) template <typename Return2, typename ... Args2>
function_ref(Return2(*)(Args2...) fptr);
type_safe::function_ref<Return(Args...)>::function_ref
template <typename Functor>
function_ref(const Functor& f);
Effects: Creates a reference to the function created by the stateless lambda.
Notes: This constructor is intended for stateless lambdas, which are implicitly convertible to function pointers. It does not participate in overload resolution, unless the type is implicitly convertible to a function pointer that is compatible with the specified signature.
Notes: Due to to implementation reasons, it does not work for polymorphic lambdas, it needs an explicit cast to the desired function pointer type. A polymorphic lambda convertible to a direct match function pointer, works however.
type_safe::function_ref<Return(Args...)>::function_ref
template <typename Functor>
function_ref(Functor& f);
Effects: Creates a reference to the specified functor. It will store a pointer to the function object, so it must live as long as the reference.
Notes: This constructor does not participate in overload resolution, unless the functor is compatible with the specified signature.
type_safe::function_ref<Return(Args...)>::function_ref
template <typename Return2, typename ... Args2>
function_ref(const function_ref<Return2(Args2...)>& other, 'hidden' = 0);
Converting copy constructor.
Effects: Creates a reference to the same function referred by other
.
Notes: This constructor does not participate in overload resolution, unless the signature of other
is compatible with the specified signature.
Notes: This constructor may create a bigger conversion chain. For example, if other
has signature void(const char*)
it can refer to a function taking std::string
. If this signature than accepts a type T
implicitly convertible to const char*
, calling this will call the function taking std::string
, converting T -> std::string
, even though such a conversion would be ill-formed otherwise. \param 1 \exclude
type_safe::function_ref<Return(Args...)>::assign
template <typename Functor>
void assign(Functor&& f) noexcept;
Effects: Rebinds the reference to the specified functor.
Notes: This assignment operator only participates in overload resolution, if the argument can also be a valid constructor argument.
type_safe::function_ref<Return(Args...)>::operator()
Return operator()(Args... args) const;
Effects: Invokes the stored function with the specified arguments and returns the result.